package com.ganmiao.server.sys.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ganmiao.exception.DefaultBusinessException;
import com.ganmiao.server.file.service.GmAttachmentService;
import com.ganmiao.server.file.vo.GmAttachmentVo;
import com.ganmiao.server.sys.entity.SysMenu;
import com.ganmiao.server.sys.query.SysMenuQuery;
import com.ganmiao.server.sys.repository.SysMenuRepository;
import com.ganmiao.server.sys.vo.SysMenuVo;
import com.ganmiao.server.sys.vo.SysUserVo;
import com.ganmiao.server.user.context.UserAuthContext;
import com.ganmiao.server.user.enums.SysCodeEnum;
import com.ganmiao.utils.StatusUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 菜单信息
 */
@Service
public class SysMenuService {

    //菜单信息
    @Autowired
    private SysMenuRepository sysMenuRepository;

    //角色菜单信息
    @Autowired
    private SysRoleMenuService sysRoleMenuService;

    @Autowired
    private GmAttachmentService gmAttachmentService;

    /**
     * 修改显示排序
     *
     * @param parentId
     * @param menuOrder
     * @return
     */
    public boolean updateMenuOrder(Integer parentId, Integer menuOrder, String menuList) {

        //获取系统编码
        String sysCode = UserAuthContext.getSysCode();

        //修改条件
        LambdaUpdateWrapper<SysMenu> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(SysMenu::getSysCode, sysCode)
                .eq(SysMenu::getParentId, parentId)
                .eq(SysMenu::getMenuList, menuList)
                .eq(SysMenu::getStatus, StatusUtils.PASS)
                .gt(SysMenu::getMenuOrder, menuOrder)
                .setSql("menu_order = menu_order + 1");

        return sysMenuRepository.update(updateWrapper);

    }

    /**
     * 验证同级菜单是否存在
     *
     * @param menuName
     * @param parentId
     * @return
     */
    public boolean verifySysMenuIsExist(String menuName, Integer parentId, String menuList) {

        //获取系统编码
        String sysCode = UserAuthContext.getSysCode();

        //查询条件
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getSysCode, sysCode)
                .eq(SysMenu::getMenuName, menuName)
                .eq(SysMenu::getParentId, parentId)
                .eq(SysMenu::getMenuList, menuList)
                .eq(SysMenu::getStatus, StatusUtils.PASS);
        SysMenu one = sysMenuRepository.getOne(queryWrapper);

        return !Objects.isNull(one);

    }

    /**
     * 获取子菜单
     *
     * @param parentId
     * @param sysMenuList
     */
    public List<SysMenuVo> getChildMenu(Integer parentId, List<SysMenu> sysMenuList) {

        //返回数据
        List<SysMenuVo> childMenus = new ArrayList<>();

        // 遍历所有节点，将父菜单id与传过来的id比较，相同则存入返回数据中
        sysMenuList.forEach(item -> {

            if (item.getParentId().equals(parentId)) {

                SysMenuVo sysMenuVo = new SysMenuVo();
                BeanUtils.copyProperties(item, sysMenuVo);
                if (item.getMenuLog() != null) {
                    sysMenuVo.setMenuLogUrl(gmAttachmentService.getByFileId(item.getMenuLog()).getFileUrl());
                }
                childMenus.add(sysMenuVo);

            }

        });


        // 把子菜单的子菜单再循环一遍
        if (!CollectionUtils.isEmpty(childMenus)) {

            for (SysMenuVo child : childMenus) {

                child.setChildren(getChildMenu(child.getMenuId(), sysMenuList));

            }

        }

        //数据为空则停止循环
        if (childMenus.size() == 0) {

            return new ArrayList<>();

        }

        return childMenus;

    }

    /**
     * 新增菜单信息
     *
     * @param sysMenu
     * @return
     */
    @Transactional
    public boolean addSysMenu(SysMenu sysMenu) {

        //获取系统编码并赋值
        String sysCode = UserAuthContext.getSysCode();
        sysMenu.setSysCode(sysCode);

        //验证同级菜单是否存在
        if (verifySysMenuIsExist(sysMenu.getMenuName(), sysMenu.getParentId(), sysMenu.getMenuList())) {

            throw new DefaultBusinessException("同级菜单已存在");

        }

        //修改显示排序
        updateMenuOrder(sysMenu.getParentId(), sysMenu.getMenuOrder(), sysMenu.getMenuList());

        return sysMenuRepository.save(sysMenu);

    }

    /**
     * 删除菜单信息
     *
     * @param menuId
     * @return
     */
    @Transactional
    public boolean deleteSysMenu(@NotNull(message = "菜单主键ID不能为空") Integer menuId) {

        //删除条件
        LambdaUpdateWrapper<SysMenu> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(SysMenu::getMenuId, menuId)
                .or()
                .in(SysMenu::getParentId, menuId)
                .set(SysMenu::getStatus, StatusUtils.FAILURE);

        //删除角色菜单信息
        sysRoleMenuService.deleteSysRoleMenuByMenuId(menuId);

        return sysMenuRepository.update(updateWrapper);

    }

    /**
     * 修改菜单信息
     *
     * @param sysMenu
     * @return
     */
    @Transactional
    public boolean updateSysMenu(SysMenu sysMenu) {

        //获取菜单信息
        SysMenu menu = sysMenuRepository.getById(sysMenu.getMenuId());

        //验证同级菜单名称是否修改和同级菜单是否存在
        if (!menu.getMenuName().equals(sysMenu.getMenuName()) && verifySysMenuIsExist(sysMenu.getMenuName(), sysMenu.getParentId(), sysMenu.getMenuList())) {

            throw new DefaultBusinessException("同级菜单已存在");

        }
        if (!Objects.equals(menu.getMenuOrder(), sysMenu.getMenuOrder())) {
            //修改显示排序
            updateMenuOrder(sysMenu.getParentId(), sysMenu.getMenuOrder(), sysMenu.getMenuList());
        }

        return sysMenuRepository.updateById(sysMenu);

    }

    /**
     * 获取菜单信息 (分页)
     *
     * @param sysMenuQuery
     * @return
     */
    public List<SysMenuVo> getSysMenuList(SysMenuQuery sysMenuQuery) {

        //获取系统编码
        String sysCode = UserAuthContext.getSysCode();

        //返回数据
        List<SysMenuVo> sysMenuVoList = new ArrayList<>();

        //菜单名称不为空 (条件查询)
        if (StringUtils.isNotBlank(sysMenuQuery.getMenuName())) {

            //查询条件
            LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SysMenu::getSysCode, sysCode)
                    .eq(SysMenu::getMenuList, StringUtils.isNotBlank(sysMenuQuery.getMenuList()) ? sysMenuQuery.getMenuList() : "0")
                    .eq(SysMenu::getStatus, StatusUtils.PASS)
                    .like(SysMenu::getMenuName, sysMenuQuery.getMenuName())
                    .orderByAsc(SysMenu::getMenuOrder);
            //查询结果
            List<SysMenu> parentResult = sysMenuRepository.list(queryWrapper);

            // 获取一级菜单
            if (!parentResult.isEmpty()) {

                //结果拷贝
                for (SysMenu sysMenu : parentResult) {

                    boolean anyMatch = parentResult.stream().anyMatch(item -> item.getMenuId().equals(sysMenu.getParentId()));
                    if (!anyMatch) {
                        SysMenuVo sysMenuVo = new SysMenuVo();
                        BeanUtils.copyProperties(sysMenu, sysMenuVo);
                        if (sysMenu.getMenuLog() != null) {
                            sysMenuVo.setMenuLogUrl(gmAttachmentService.getByFileId(sysMenu.getMenuLog()).getFileUrl());
                        }
                        sysMenuVoList.add(sysMenuVo);
                    }

                }

                //获取子菜单
                if (!sysMenuVoList.isEmpty()) {

                    sysMenuVoList.forEach(item -> {

                        item.setChildren(getChildMenu(item.getMenuId(), parentResult));

                    });

                }

            }

            return sysMenuVoList;

        }

        //查询条件
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getSysCode, sysCode)
                .eq(SysMenu::getMenuList, StringUtils.isNotBlank(sysMenuQuery.getMenuList()) ? sysMenuQuery.getMenuList() : "0")
                .eq(SysMenu::getStatus, StatusUtils.PASS)
                .eq(SysMenu::getParentId, 0)
                .orderByAsc(SysMenu::getMenuOrder);
        //查询结果
        List<SysMenu> parentResult = sysMenuRepository.list(queryWrapper);

        // 获取一级菜单
        if (!parentResult.isEmpty()) {

            //结果拷贝
            parentResult.forEach(item -> {

                SysMenuVo sysMenuVo = new SysMenuVo();
                BeanUtils.copyProperties(item, sysMenuVo);
                if (item.getMenuLog() != null) {
                    GmAttachmentVo attachmentVo = gmAttachmentService.getByFileId(item.getMenuLog());
                    sysMenuVo.setMenuLogUrl(Objects.nonNull(attachmentVo) ? attachmentVo.getFileUrl() : null);
                }
                sysMenuVoList.add(sysMenuVo);

            });


            //查询条件
            queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SysMenu::getSysCode, sysCode)
                    .eq(SysMenu::getStatus, StatusUtils.PASS)
                    .ne(SysMenu::getParentId, 0)
                    .orderByAsc(SysMenu::getMenuOrder);
            //查询结果
            List<SysMenu> sysMenuList = sysMenuRepository.list(queryWrapper);

            //获取子菜单
            if (!sysMenuVoList.isEmpty()) {

                sysMenuVoList.forEach(item -> {

                    item.setChildren(getChildMenu(item.getMenuId(), sysMenuList));

                });

            }
        }

        return sysMenuVoList;

    }

    /**
     * 获取菜单信息 (详情)
     *
     * @param menuId
     * @return
     */
    public SysMenuVo getSysMenu(@NotNull(message = "菜单主键ID不能为空") Integer menuId) {

        SysMenu byId = sysMenuRepository.getById(menuId);
        SysMenuVo sysMenuVo = new SysMenuVo();
        BeanUtils.copyProperties(byId, sysMenuVo);
        if (byId.getMenuLog() != null) {
            sysMenuVo.setMenuLogUrl(gmAttachmentService.getByFileId(byId.getMenuLog()).getFileUrl());
        }
        return sysMenuVo;
    }

    /**
     * 获取菜单信息 (多详情)
     *
     * @param menuIds
     * @return
     */
    public List<SysMenuVo> getSysMenuByIds(List<Integer> menuIds) {
        //返回数据
        List<SysMenuVo> list = new ArrayList<>();

        if (menuIds.isEmpty()) {
            return list;
        }

        //查询条件
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysMenu::getMenuId, menuIds)
                .eq(SysMenu::getStatus, StatusUtils.PASS)
                .orderByAsc(SysMenu::getMenuOrder);
        //查询结果
        List<SysMenu> sysMenuList = sysMenuRepository.list(queryWrapper);

        //获取角色菜单ID
        sysMenuList.forEach(item -> {

            //获取一级菜单
            if (item.getParentId().equals(0)) {

                SysMenuVo sysMenuVo = new SysMenuVo();
                BeanUtils.copyProperties(item, sysMenuVo);
                list.add(sysMenuVo);

            }

        });

        //获取子菜单
        if (!list.isEmpty()) {

            list.forEach(item -> {

                item.setChildren(getChildMenu(item.getMenuId(), sysMenuList));

            });

        }

        return list;

    }

    /**
     * 获取供应商菜单ID集合
     *
     * @return
     */
    public List<Integer> getSupplierMenuIds(String menuList) {
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getStatus, StatusUtils.PASS);
        queryWrapper.eq(SysMenu::getMenuList, menuList);
        queryWrapper.eq(SysMenu::getSysCode, SysCodeEnum.SUPPLIER.getCode());
        return sysMenuRepository.list(queryWrapper).stream().map(SysMenu::getMenuId).collect(Collectors.toList());
    }

    /**
     * 获取商超菜单ID集合
     *
     * @return
     */
    public List<Integer> getShopMenuIds(String menuList) {
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getStatus, StatusUtils.PASS);
        queryWrapper.eq(SysMenu::getMenuList, menuList);
        queryWrapper.eq(SysMenu::getSysCode, SysCodeEnum.SUPERMARKET.getCode());
        return sysMenuRepository.list(queryWrapper).stream().map(SysMenu::getMenuId).collect(Collectors.toList());
    }

}
